#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @FileName  :fn_db.py
# @Time      :2024/11/8 22:35
# @Author    :zhou_yi

"""
 与Mongo数据库增删改查有关的二次封装函数
"""

import asyncio
from io import BytesIO
from datetime import datetime
from db.async_mongoDB import Work, Files


class _DB:
    def __init__(self):
        self.db = Work
        self.collection = ''

    @staticmethod  # id 与 _id 的转换
    def _handle_id_of_data(data: dict) -> dict:
        """
            对数据字典
             1.保障传递的字典必须 有 id 或 _id 键值对
             2.id 转换 _id ,_id 不操作
        :param data:
        :return:
        """

        if data.get('id'):
            data.update({'_id': data['id']})
            data.pop('id')
            return data

        else:
            if data.get('_id'):
                return data
            else:
                raise '数据不正确,没有id属性'

    # 集合中最大的ID 前提是 该集合的id是命名的 (字母-编号)的形式,
    async def max_id_and_new_id(self, sep='-') -> tuple[str, str]:
        return await self.db.collection_max_id_and_new_id(self.collection, sep)

    # 单数据 返回 主键id
    async def insert_one(self, data: dict) -> tuple[bool, any]:
        """
            返回 主键id
        """
        data = self._handle_id_of_data(data)
        res = await self.db.insert_one(self.collection, data)
        return res

    # 多数据 返回 主键 ids 列表
    async def insert_many(self, data: list[dict]) -> tuple[bool, list]:
        """
            返回 主键 ids 列表
        """
        data = [self._handle_id_of_data(item) for item in data]
        res = await self.db.insert_many(self.collection, data)
        return res

    # 单数据修改 返回 主键id
    async def update_one(self, query, data: dict) -> tuple[bool, int, any]:
        """
            返回
        """
        return await self.db.update_one(self.collection, query, data)

    # 多数据修改 成功 和 数量 主键列表
    async def update_many(self, query, data: dict) -> tuple[bool, int, list]:
        """
            返回 元组 成功,数量
        """
        return await self.db.update_many(self.collection, query, data)

    # 删除单条 返回主键
    async def delete_one(self, query) -> tuple[bool, int, any]:
        return await self.db.delete_one(self.collection, query)

    # 删除多条 返回主键列表
    async def delete_many(self, query) -> tuple[bool, int, list]:
        return await self.db.delete_many(self.collection, query)


class CompanyDB(_DB):
    def __init__(self):
        super().__init__()
        self.collection = 'company'

    # 按名称查找公司 单查询结果
    async def fetch_by_name(self, name: str) -> dict:
        res: dict = await self.db.fetch_one(self.collection, {'name': name})
        return res

    # 正则查找相关公司 多查询结果
    async def fetch__by_relation(self, *relation) -> list[dict]:
        # 创建 查询条件
        pattern = ".*"
        for itm in relation:
            pattern = pattern + itm + '.*'
        query = {"relation": {"$regex": pattern}}

        # 生成查询结果 返回异步对象
        async_cursor = self.db.fetch_many(self.collection, query)  # 异步对象

        # 对异步对象做进一步处理(比如排序，分页....)
        ...

        res: list[dict] = await async_cursor.to_list()
        return res


class AddressDB(_DB):
    def __init__(self):
        super().__init__()
        self.collection = 'address'

    # 名称查找点位 单查询结果
    async def fetch_by_point(self, point: str) -> dict:
        res: dict = await self.db.fetch_one(self.collection, {'point': point})
        return res

    # 按客户查找点位 多查询结果
    async def fetch_by_custom(self, custom: str) -> list[dict]:
        async_cursor = self.db.fetch_many(self.collection, {'custom': custom})  # 异步对象
        res: list[dict] = await async_cursor.to_list()
        return res


class ClearWasterRecordsDB(_DB):
    def __init__(self):
        super().__init__()
        self.collection = 'clear_waster_records'

    # 点位外键查询 多查询结果
    async def fetch_by_fk(self, fk: str) -> list[dict]:
        async_cursor = self.db.fetch_many(self.collection, {'fk': fk})  # 异步对象
        res: list[dict] = await async_cursor.to_list()
        return res

    # 时间范围查询记录 多查询结果
    async def fetch_by_fk_and_timeframe(self, fk: str, start: datetime, end: datetime) -> list[dict]:
        query = {'fk': fk,
                 'datetime': {
                     "$gte": start,
                     "$lte": end
                 }}

        async_cursor = self.db.fetch_many(self.collection, query)  # 异步对象

        res: list[dict] = await async_cursor.to_list()
        return res


class _FS:
    def __init__(self):
        self.fs = Files
        self.collection = ''

    # 查找文件
    async def find_one(self, query):
        return await self.fs.find_one(self.collection, query)

    # 删除文件 根据文件名删除
    async def delete(self, filename: str) -> None:
        _exist = await self.find_one({'filename': filename})  # 查找id
        if _exist:
            await self.fs.delete(self.collection, _exist._id)  # 存在删除
        else:
            pass

    # 存储文件 同名文件覆盖
    async def put(self, data: bytes, filename: str):
        _id = await self.fs.put(self.collection, data, filename)
        return _id


class AddressFS(_FS):
    def __init__(self):
        super().__init__()
        self.collection = 'address'

    async def insert_many_by_pointID(self, pointID, data: list[bytes]) -> int:
        for idx, b in enumerate(data, 1):
            filename = f"{pointID}_{idx}.png"
            _res = await self.put(b, filename)
        return len(data)

    # 查找某点位对应的图片 p-1003_1.png p-1003_2.png ...
    async def fetch_many_by_pointID(self, pointID) -> list[dict]:
        _lst = await self.fs.find_many(self.collection, query={'filename': {'$regex': f'^{pointID}.*'}})

        res = []
        for itm in _lst:
            _dic = {}
            _dic.update({
                'file_id': itm._id.__str__(),
                'filename': itm.filename,
                'content': await itm.read()
            })
            res.append(_dic)
        return res

    # 删除某点位对应的图片
    async def delete_many_by_pointID(self, pointID) -> int:
        _lst = await self.fs.find_many(self.collection, {'filename': {'$regex': f'^{pointID}.*'}})
        for itm in _lst:
            await self.fs.delete(self.collection, file_id=itm._id)
        return len(_lst)


class ClearWasterRecordsFS(_FS):
    def __init__(self):
        super().__init__()
        self.collection = 'clear_waster_records'

    # 增加点位某天的记录图片
    async def insert_many_by_fk_date(self, fk: str, dt: str, data: list[bytes]) -> int:
        dt = datetime.strptime(dt, "%Y-%m-%d")
        file_prefix = f"{fk}_{dt.year}_{dt.month}_{dt.day}"
        for idx, b in enumerate(data, 1):
            filename = f"{file_prefix}_{idx}.png"
            _res = await self.put(b, filename)
        return len(data)

    # 查找某点位某一天记录的图片
    async def fetch_many_by_fk_date(self, fk: str, dt: str) -> list[dict]:
        dt = datetime.strptime(dt, "%Y-%m-%d")
        name = f"{fk}_{dt.year}_{dt.month}_{dt.day}"
        _lst = await self.fs.find_many(self.collection, {'filename': {'$regex': f'^{name}.*'}})
        res = []
        for itm in _lst:
            _dic = {}
            _dic.update({
                'file_id': itm._id.__str__(),
                'filename': itm.filename,
                'content': await itm.read()
            })
            res.append(_dic)
        return res

    # 删除某点位某一天记录的图片
    async def delete_many_by_fk_date(self, fk: str, dt: str) -> int:

        dt = datetime.strptime(dt, "%Y-%m-%d")
        name = f"{fk}_{dt.year}_{dt.month}_{dt.day}"
        _lst = await self.fs.find_many(self.collection, {'filename': {'$regex': f'^{name}.*'}})
        for itm in _lst:
            await self.fs.delete(self.collection, file_id=itm._id)

        return len(_lst)

    # 删除某点位所有清运记录图片
    async def delete_many_by_fk(self, fk) -> int:
        _lst = await self.fs.find_many(self.collection, {'filename': {'$regex': f'^{fk}.*'}})
        for itm in _lst:
            await self.fs.delete(self.collection, file_id=itm._id)

        return len(_lst)


# 单例
companyDB = CompanyDB()
addressDB = AddressDB()
clearWasterRecordsDB = ClearWasterRecordsDB()

addressFS = AddressFS()
clearWasterRecordsFS = ClearWasterRecordsFS()

if __name__ == '__main__':
    # print(asyncio.run(companyDB.fetch_by_name('北京盈兆鑫再生资源回收市场有限公司')))
    # print(asyncio.run(companyDB.fetch__by_relation('有害垃圾', '清运')))
    # print(asyncio.run(companyDB.max_id_and_new_id()))
    tst_d = [{'id': 'a-0001', 'v': 100}, {'id': 'a-0002', 'v': 200}, {'id': 'a-0003', 'v': 300}]
    _d1 = {
        "id": "c-0007",
        "ABC": "顺商集团",
        "name": "北京顺义商业集团有限公司",
        "jur_person": "李浩",
        "address": "北京市顺义区仁和地区府前西街1号1幢6层",
        "tax": "91110113MA00DQ6D3C",
        "bank": "北京银行顺义支行",
        "account": "20000034428100016343054",
        "tel_1": "010-81487888",
        "relation": "有害垃圾-清运",
        "user": "",
        "tel_2": ""
    }
    _d2 = {
        "id": "p-1001",
        "point": "顺商总部",
        "long": 116.6575683,
        "lat": 40.1348536,
        "name": "顺商总部",
        "customID": "c-0006",
        "custom": "顺商集团",
        "part": "顺商总部",
        "manager": "孟远",
        "tel": "13681203547",
        "notice": "进大门右转",
        "address": "北京市顺义区新顺南大街5号",
        "code": "#"
    }
    _d3 = {
        "_id": "f989cd03-a99b-47a6-b8fa-49a93b737f1b",
        "fk": "p-1034",
        "datetime": datetime(2024, 11, 12, 17, 22, 35),
        "is_really": 1,
        "w1": 15,
        "w2": 16,
        "w3": 17,
        "w4": 18,
        "w5": 19,
        "w6": 20,
        "w7": 21,
        "w8": 22
    }

    ...
